﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace Ipmce.RemoteVoting.Common.Tools.CardReader.Utils
{
	public static class CardUtils
	{
		private const int FacialHeaderSize = 14;
		private const int FacialInformationSize = 20;
		private const int ImageInformationSize = 12;
/*
		private const int FeaturePointSize = 8;
*/

		public static byte[] ExtractPhoto(byte[] rawData)
		{
			var cbeffHeaderSize = GetHeaderSize(rawData);
			return rawData.Skip(FacialHeaderSize + cbeffHeaderSize + FacialInformationSize + ImageInformationSize).ToArray();
		}

		private static int GetHeaderSize(IList<byte> rawData)
		{
			//Проверка корректности CBEFF заголовка и нахождение его конца

			//в начале должны быть байты 75 82 (LDS)
			if (!rawData.Take(2).SequenceEqual(new byte[] {0x75, 0x82}))
			{
				throw new Exception("Parsing  error");
			}

			//далее 2 байта = (размер всего буфера - offset - 2) 
			var pailoadLength = (short) (rawData.Count - 4);
			if (!rawData.Skip(2).Take(2).SequenceEqual(ConvertToArray(pailoadLength)))
			{
				throw new Exception("Parsing  error");
			}

			//далее 3 байта должны быть 7F 61 82(LDS/ISO)
			if (!rawData.Skip(4).Take(3).SequenceEqual(new byte[] {0x7f, 0x61, 0x82}))
			{
				throw new Exception("Parsing  error");
			}

			var offset = 7;
			//далее 2 байта = (размер всего буфера - offset - 2)
			pailoadLength = (short) (rawData.Count - offset - 2); 
			if (!rawData.Skip(offset).Take(2).SequenceEqual(ConvertToArray(pailoadLength)))
			{
				throw new Exception("Parsing  error");
			}

			offset+=2;
			//далее 3 байта 02 01 01(? вообще говоря количество фотографий...в нашем случае 1 для общего случая нужна сложная проверка)
			if (!rawData.Skip(offset).Take(3).SequenceEqual(new byte[] {0x02, 0x01, 0x01}))
			{
				throw new Exception("Parsing  error");
			}

			offset+=3;
			//далее 3 байта должны быть 7F 60 82(LDS/ISO)
			if (!rawData.Skip(offset).Take(3).SequenceEqual(new byte[] { 0x7f, 0x60, 0x82 }))
			{
				throw new Exception("Parsing  error");
			}

			offset+=3;
			//далее 2 байта = (размер всего буфера - offset - 2)
			pailoadLength = (short) (rawData.Count - offset - 2);
			if (!rawData.Skip(offset).Take(2).SequenceEqual(ConvertToArray(pailoadLength)))
			{
				throw new Exception("Parsing  error");
			}

			offset+=2;
			//следующий байт A1 или A2 - тип темплейта 
			if (!rawData.Skip(offset).Take(1).SequenceEqual(new byte[] { 0xA1 }) &&
				!rawData.Skip(offset).Take(1).SequenceEqual(new byte[] { 0xA2 }))
			{
				throw new Exception("Parsing  error");
			}

			//var templateType = rawData[offset];
			offset++;
			/*следующий байт типа длина биометрического шаблона (Biometrical Template Size)
			вообщем пока не вижу глубокого смысла его разбирать,
			так как там всего пара тегов необходимо. на потом.
			*/
			var templateSize = rawData[offset];
			offset++;
			//if(!CheckCorrectBiometricalTempate(dg2Buf+offset, templateSize, templateType))
			//{
			//    throw new Exception("Parsing  error");
			//}

			offset += templateSize;
			/*cледующие три байта по LDS либо 5F 2E либо 7F 2E  (82)*/
			if(!rawData.Skip(offset).Take(3).SequenceEqual(new byte[] { 0x5f, 0x2e, 0x82 }) &&
				!rawData.Skip(offset).Take(3).SequenceEqual(new byte[] { 0x7f, 0x2e, 0x82 }))
			{
				throw new Exception("Parsing  error");
			}

			offset+=3;
			//далее опять 2 байта = (размер всего буфера - offset - 2)
			pailoadLength = (short) (rawData.Count - offset - 2);
			if (!rawData.Skip(offset).Take(2).SequenceEqual(ConvertToArray(pailoadLength)))
			{
				throw new Exception("Parsing  error");
			}

			offset+=2;
			//Ура! 
			return offset;
		}

		private static IEnumerable<byte> ConvertToArray(short data)
		{
			return new[] { (byte)((data & 0xff00) >> 8), (byte)(data & 0xff), };
		}
	}
}
